parktype_summary <- table(ob_park$parkClass)
ggplot(
data = ob_park,
mapping = aes(y = parkClass)
) +
labs(
caption = "Bar graph 1"
) +
geom_bar()
This project analyzes Baltimore’s park accessibility and its relationship with demographics (population density, race, and income), addressing critical intersections of urban planning and environmental justice. Historical inequities, including segregation and economic disparities, could have created uneven access to parks, which are vital for physical, mental, and social well being. For individuals with disabilities, access to these spaces can profoundly affect their quality of life. Accessibility ensures that everyone has the chance to experience the mental and physical health benefits of outdoor activities.(“Accessibility in Parks and Recreational Areas Under ADA - KNOW-THE-ADA,” n.d.)
Through walkability isochrone analysis and demographic correlations can identify access gaps and inform strategies for more equitable urban green spaces.
Data Collection:
Spatial Analysis:
Visualization:
Equity Assessment:
Insights and Explanation:
Limitations: MAUP: tracts are considered for analysis, so the emphasis is given to the census tracts. May not fully capture the socio-political processes influencing current disparities in green space access. Primarily addresses proximity and walkability, omitting factors like affordability, programming, or cultural inclusivity.
Information: code is referred from R documentation using ? used sf functions in the major operations. provided citations and other LLM references at code chunks
The Baltimore boundary was extracted using the Tigris package, and park data was obtained from the Open Baltimore download link(“Park Dataset,” n.d.). Transformations were performed to ensure alignment with the other objects.
The ob_parks dataset includes the following park categories some observations are Mini Parks and Neighborhood Parks lead with the highest counts. Other park types, such as Green Spaces and Citywide Parks, have moderate representation. Special Use Facilities and Civic Spaces are the least common. Parks from Alternate Providers generally have lower counts across all classes. Alternate Providers include private organizations, community groups, or non-profits offering access to parks or green spaces.
parktype_summary <- table(ob_park$parkClass)
ggplot(
data = ob_park,
mapping = aes(y = parkClass)
) +
labs(
caption = "Bar graph 1"
) +
geom_bar()
# Filter population and race data for analysis
balt_trct_pop22 <- balt_pop_22 |>
filter(variable == "total_population") |> st_transform(crs = 3857)
#View(balt_trct_pop22)
balt_black_pop22 <- balt_pop_22 |>
filter(variable == "Black_pop") |> st_transform(crs = 3857)
balt_white_pop22 <- balt_pop_22 |>
filter(variable == "White_pop") |> st_transform(crs = 3857)
# Calculate the percentage of Black and White populations
balt_black_percent <- balt_black_pop22 |>
mutate(percent_black = (estimate / balt_trct_pop22$estimate) * 100)
balt_white_percent <- balt_white_pop22 |>
mutate(percent_white = (estimate/balt_trct_pop22$estimate)*100)
# View(balt_trct_pop22)Used scale_fill_manual to create legends in the plot. (“Create Your Own Discrete Scale Scale_manual,” n.d.)
# Map of parks in Baltimore along with the tracts
ggplot() +
geom_sf(data = balt_trct_pop22, fill = NA , color = "black") +
geom_sf(data = ob_park, aes(fill = "Parks"), color = "black", size = 0.3) +
scale_fill_manual(
name = "Legend",
values = c("Parks" = "green")
) +
labs(title = "Parks in Baltimore", caption = "Figure 1") +
theme_minimal()
Inspired by the [“Urban Spatial. Urban Spatial” (n.d.); ] Urban Spatial project on equitable park access, this analysis explores park accessibility in Baltimore by examining how close census tracts are to the nearest park. To simplify the calculations, parks are represented as points rather than polygons, focusing on proximity rather than park size or shape. The geographic center of each census tract, or centroid, is used as a stand-in for where people live within the tract. By measuring the distance between these centroids and park points, tracts are classified as either “Near Park” or “Far from Park” based on a threshold of 800 meters. This approach helps uncover disparities in park access and supports thoughtful, equity-driven urban planning.
The summary shows the count of the tracts where the park is far or near to the centroid of the tract.
# Summary of classification
summary22 <- table(balt_trct_pop22$distance_type)
summary22
Far from park Near Park
23 176
# Plot census tracts classified by distance to parks
ggplot(data = balt_trct_pop22) +
geom_sf(aes(fill = distance_type), color = "black", size = 0.1) +
scale_fill_manual(
values = c("Near Park" = "green", "Far from park" = "blue"),
name = "Park Access"
) +
labs(
title = "Census tracts classified by proximity to parks, 2022",
caption = "Figure 2"
) +
theme_void()
# Calculate area of census tracts (in sq kilometers)
balt_trct_pop22$area_sq_km <- as.numeric(st_area(balt_trct_pop22) / 10^6)
# Calculate population density (people per sq kilometer)
balt_trct_pop22$pop_density <- balt_trct_pop22$estimate / balt_trct_pop22$area_sq_km
# View(balt_trct_pop22)ggplot(balt_trct_pop22) +
geom_boxplot(aes(x = distance_type, y = pop_density, fill = distance_type)) +
scale_fill_manual(values = c("blue", "green")) +
labs(
title = "Population Density by Park Access",
x = "Park Access",
y = "Population Density (people per square km)",
caption = "Plot 1"
) +
theme_minimal()
Population Density:
On average, census tracts near parks have a higher population density (2599.649 people/km²). Tracts far from parks have a lower average population density (1694.107 people/km²).
This result could indicate that parks are more accessible in denser, urbanized areas, while less dense areas may have fewer nearby parks.
As per, (Buckley 2009)A higher proportion of African Americans have access to parks within walking distance, defined as 400 meters or less, than whites, but whites have access to more acreage of parks within walking distance than blacks.
# Plot racial demographics comparison by park access
ggplot(balt_trct_pop22) +
geom_boxplot(aes(x = distance_type, y = percent_black, fill = distance_type)) +
scale_fill_manual(values = c("blue", "green")) +
labs(
title = "Black Population Percentage by Park Access",
x = "Park Access",
y = "Black Population Percentage",
caption = "Plot 2"
) +
theme_minimal()
ggplot(balt_trct_pop22) +
geom_boxplot(aes(x = distance_type, y = percent_white, fill = distance_type)) +
scale_fill_manual(values = c("blue", "green")) +
labs(
title = "White Population Percentage by Park Access",
x = "Park Access",
y = "White Population Percentage",
caption = "Plot 3"
) +
theme_minimal()
Based on the preliminary analysis, tracts closer to parks show a higher percentage of Black residents and a lower percentage of White residents compared to tracts farther from parks.
This suggests that Black residents in Baltimore may have better proximity to parks compared to White residents.
While I have not done in depth survey, the initial results appear to align with findings from existing research, which suggests disparities in park access and park acreage across different racial groups in Baltimore.
Studies have shown that low-income neighborhoods, often with higher minority populations, may have less access to quality parks (“Spatial Disparities in the Distribution of Parks and Green Spaces in the USA Annals of Behavioral Medicine,” n.d.)Spatial Disparities in the Distribution of Parks and Green Spaces in the USA | So the income analysis could provide insights about it.
ggplot(btrct_joined |>
filter(variable.x == "median_income"), aes(x = distance_type, y = estimate.x)) +
geom_boxplot(aes(fill = distance_type)) +
scale_fill_manual(values = c("blue", "green")) +
labs(
title = "Boxplot of Median Income by Park Access",
x = "Park Access",
y = "Median Income",
caption = "Plot 4"
) +
theme_minimal()Warning: Removed 3 rows containing non-finite outside the scale range
(`stat_boxplot()`).

The median household income is slightly higher in areas farther from parks compared to those nearer.
The boxplot visualization indicates that the distribution of median incomes is relatively similar regardless of proximity to parks, with no significant outliers or variations.
These findings suggest that, in Baltimore, proximity to parks does not significantly correlate with median household income. This could indicate equitable physical access to parks across different income levels. The code to only filter the tracts without parks is drawn from AI (“Chatgpt_promt,” n.d.)
ggplot() +
geom_sf(data = tracts_without_parks, aes(fill = "Tracts with no Parks"), color = "black") +
geom_sf(data = balt_trct_pop22, fill = NA, color = "black") +
geom_sf(data = ob_park, aes(fill = "Parks"), color = "darkgreen") +
scale_fill_manual(
name = "Legend",
values = c("Tracts with no Parks" = "red", "Parks" = "green")) +
labs(
title = "Baltimore tracts with no parks",
caption = "figure 3"
) +
theme_minimal()
# Mapview of tracts without parks
mapview(tracts_without_parks, col.regions = "red") + mapview(ob_park, col.regions = "green") + mapview(balt_trct_pop22, alpha.regions = 0 )An analysis of Baltimore’s census tracts reveals that 35 out of 199 tracts lack parks, indicating that approximately 17.6% of the city’s neighborhoods may have limited access to green spaces. This finding underscores the need for targeted urban planning to enhance park accessibility and promote equitable distribution of recreational areas across all communities.
parks_tract_intersect <- st_intersection(balt_trct_pop22, ob_park)Warning: attribute variables are assumed to be spatially constant throughout
all geometries
#View(parks_tract_intersect)
tract_park_size <- parks_tract_intersect |>
group_by(GEOID) |>
summarise(total_parkarea = sum(prkAcreage, na.rm = TRUE))
# As two sf objects cannot be joined, I want to join using a column, dataframe is used
balt_trct_pop22_df <- balt_trct_pop22_df |>
left_join(tract_park_size, by = "GEOID")
balt_trct_pop22_sf <- st_as_sf(balt_trct_pop22_df)
summary(tract_park_size$total_parkarea) Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0863 3.9070 22.0284 147.5446 127.2659 1122.7252
Baltimore’s census tracts show an uneven distribution of park areas, with a few neighborhoods containing large green spaces while most have minimal parkland. This pattern creates disparities in recreational access across different parts of the city.
The main goal is to analyze the accessibility of parks in Baltimore for various travel modes (walking, cycling, driving) within specific time intervals (5, 10, and 15 minutes). This can be achieved with isochrones.
Isochrones are calculated using (“Openrouteservice Goes r Openrouteservice” 2018)OpenRouteService for two specific parks and one custom location.
It Combines leaflet interactive maps for qualitative insights and ggplot2 for high-quality static visualizations.
Calculating 5- and 10-minute isochrones for these parks allowed evaluation of their coverage areas.
Walking, cycling, and driving isochrones were compared to understand park accessibility from a user-defined location. By integrating park data, tract data,and multiple travel modes, It provides actionable insights.
mapview::mapview(balt_pop_22, alpha.regions = 0) + mapview(ob_park)This code is used to visually inspect and identify the desired park from the dataset (ob_park) by overlaying it with population data (balt_pop_22) on an interactive map. It helps determine the specific park location for creating isochrones by ensuring both park boundaries and population distribution are clearly visible.
As Open route services creates isochrones around the particular point, so a particular park location using park id need to be selected so that to find the walking time around it. The following code is adapted from(“Milos-Agathon/Isochrone_maps: In This Repo, i Will Show You How to Create Interactive and Static Isochrone Maps in r Using Openrouteservice, Leaflet, and Ggplot2.” n.d.) Milo’s project on isochrones, where isochrones are generated around a specific point for different travel modes. In my case, I simplified the process using custom functions to focus on a specific park location identified by its GEOID. I applied this method to analyze walking times at intervals around the selected park and explore various travel modes for the selected location. This adaptation provided a valuable learning experience, allowing me to practice working with functions and delve into the use of interactive tools like Leaflet.
For this package to work, all spatial data must be in the WGS 84 coordinate system (CRS 4326), which is required for OpenRouteService to calculate isochrones. Therefore, the parks and tracts are transformed accordingly.
For this package to run the datum should be in WGS so transforming the parks and tracts
Isolate and focus on Park-75 and tract75 spatial boundary to easily zoom into the park location and its isochrones, avoiding the need for manual searching.
Walk-ability analysis for Park-75
using the function ors_isochrones function, ischrones are retrived and then Convert isochrone walking times to minutes and simplify the polygons by grouping and intersecting overlapping areas. crop overlapping polygons to make them distinct and easier to visualize interactively in Leaflet maps.
# Filter tracts that intersect with isochrones
focused_tract75 <- balt_trct_pop22_wgs[st_intersects(balt_trct_pop22_wgs, park75_footwalking_ams_cropped, sparse = FALSE), ]Create an interactive map showing the isochrones, tracts, and Park-75 for better visualization of park accessibility. create_leafletmap function works if required attributes are provided
create_leafletmap(park75_footwalking_ams_cropped, focused_tract75, focused_park75)leaflet_map_park <- create_leafletmap(park75_footwalking_ams_cropped, focused_tract75, focused_park75) Repeated the same method for a different park
Isochrones for parkid 127
park127_balt <- get_coords(127, park_centroid_wgs)
park127_footwalking_ams <- openrouteservice::ors_isochrones(
locations = park127_balt,
profile = "foot-walking",
range = c(300, 600),
interval = 300,
api_key = api_key,
output = "sf"
)Data Processing- Adding a new column, factor and cropping for dividing the isochrone polygons, it improves the visualization.
create_leafletmap(park127_footwalking_ams_cropped, focused_tract127, focused_park127)ggplot() +
geom_sf(data = focused_tract75, fill = NA, color = "black", size = 4) +
geom_sf(data = park75_footwalking_ams, aes(fill = value/60), alpha = .5, color = "black") +
geom_sf(data = focused_park75, fill = "green", color = "black", alpha = 0.4) +
scale_fill_fermenter(
name = "Walking Time (Minutes)",
palette = "RdYlBu",
direction = 1,
) +
labs(title = "Isochrone, Park, and Tract",
subtitle = "5-10 Minute Walking Distance",
caption = "figure 4") +
theme_minimal() 
This package generates time-based isochrones around a point. By applying it to selected locations, I aim to visualize the nearest parks within 5, 10, and 15-minute intervals across different travel modes. here it is intervals are calculated in seconds [300(60*5), 900(60*15)]
create_BP_leafletmap(footwalking_SL_crop, balt_trct_pop22_wgs, ob_park_wgs,coords = coords_isochrone, title = "selected location foot walking" )create_BP_leafletmap(cycling_SL_crop, balt_trct_pop22_wgs, ob_park_wgs, coords = coords_isochrone, title = "Selected location Cycling")create_BP_leafletmap(drivingcar_SL_crop, balt_trct_pop22_wgs, ob_park_wgs, coords = coords_isochrone, title = "Selected location Driving Car" )This project highlights a notable disparity in park distribution across Baltimore. While the central part of the city has a higher density of parks that are accessible to nearby tracts, these parks are often small in size. In contrast, the northern and southern parts of the city have fewer parks relative to tract size, and some tracts lack parks entirely. Although certain areas are near parks, the limited size of these green spaces restricts their usability. Interestingly, Black communities tend to have better access to parks compared to other groups, and socioeconomic factors show minimal impact on overall park accessibility. These findings suggest that historical and planning decisions may have shaped the distribution of green spaces, underscoring the need for equitable urban planning to address these disparities.
This situation may be influenced by historical or urban planning factors that shaped the city’s green space distribution. Isochrones proved to be an effective tool for analyzing accessibility to specific locations. By generating isochrones for parks and selected points, this method can identify nearby parks within 5- to 15-minute intervals for various travel modes, such as walking, cycling, or driving. This approach offers versatility, as it can be applied to any desired location to evaluate green space accessibility comprehensively.
This project benefits a wide range of stakeholders in Baltimore. City planners and policymakers can use the findings to address disparities in park accessibility by targeting tracts with limited or no green spaces for development. Community advocacy groups focused on environmental justice may leverage the data to advocate for equitable resource allocation in underserved areas. Additionally, public health professionals can highlight the importance of walkable access to parks for improving physical and mental health, especially in neighborhoods with higher population densities or minority demographics.
The project takes a thoughtful approach to addressing park access in Baltimore, acknowledging that environmental improvements can reshape neighborhood dynamics in complex ways. By letting data tell the story of existing disparities and actively involving local residents in the conversation, the research aims to support meaningful improvements in access. The focus is on thoughtful development that lets more residents enjoy the benefits of parks - from family gatherings to exercise to quiet reflection